using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using Apache.NMS;
using System.Globalization;

namespace SimpleServiceBus.Endpoints.ActiveMQ {

    public class ActiveMQTransactionScope: IDisposable {

        //-----< Fields >-----
        //----------------------------------------------------------------------------------        
        private ISession fSession;
        private Boolean fCloseSession;
        private Boolean fCommitVote;
        private Boolean fRollbackVote;
        private IMessageProducer fProducer;
        private IDestinationResolver fDestinationResolver = new DefaultDestinationResolver();


        //-----< Constructors >-----
        //----------------------------------------------------------------------------------        
        public ActiveMQTransactionScope(IConnection connection) {
            fSession = connection.CreateSession(AcknowledgementMode.Transactional);
            fCloseSession = true;
        }

        public ActiveMQTransactionScope(ISession session) {
            if(session == null)
                throw new ArgumentNullException("session");
            fSession = session;
        }

        //-----< Public and protected properties >-----
        //----------------------------------------------------------------------------------        

        public IDestinationResolver DestinationResolver {
            get { return fDestinationResolver; }
            set { fDestinationResolver = value; }
        }

        protected IMessageProducer Producer {
            get {
                if(fProducer == null)
                    fProducer = fSession.CreateProducer();
                return fProducer;
            }
        }

        public ISession Session {
            get { return fSession; }
        }


        //-----< Public and protected methods >-----
        //----------------------------------------------------------------------------------        

        public void Commit() {
            fCommitVote = true;
        }

        public void Rollback() {
            fRollbackVote = true;
        }

        public IDestination ResolveDestination(String destination) {
            return DestinationResolver.Resolve(destination);
        }

        public void Send(IMessage message, String destination) {
            var _destination = ResolveDestination(destination);
            Send(message, _destination);
        }

        public void Send(IMessage message, IDestination destinations) {
            Send(message, destinations, true);
        }

        public void Send(IMessage message, String destination, Boolean persistent) {
            Send(message, destination, persistent, NMSConstants.defaultPriority, null);             
        }

        public void Send(IMessage message, IDestination destination, Boolean persistent) {
            Send(message, destination, persistent, NMSConstants.defaultPriority, null);
        }

        public void Send(IMessage message, String destination, Boolean persistent, MsgPriority priority, TimeSpan? timeToLive) {
            var _destination = ResolveDestination(destination);
            Send(message, _destination, persistent, priority, timeToLive);
        }

        public void Send(IMessage message, IDestination destination, Boolean persistent, MsgPriority priority, TimeSpan? timeToLive) {
            var _deliveryMode = persistent ? MsgDeliveryMode.Persistent : MsgDeliveryMode.NonPersistent;
            if(timeToLive.HasValue)
                Producer.Send(destination, message, _deliveryMode, priority, timeToLive.Value);
            else
                Producer.Send(destination, message, _deliveryMode, priority, NMSConstants.defaultTimeToLive);
        }


        //-----< Events >-----
        //----------------------------------------------------------------------------------        


        //-----< Internal members >-----
        //----------------------------------------------------------------------------------        


        //-----< Private members >-----
        //----------------------------------------------------------------------------------        


        //-----< All nested types >-----
        //----------------------------------------------------------------------------------        


        //-----< All explicit interface implementations >-----
        //----------------------------------------------------------------------------------        



        #region IDisposable Members

        public void Dispose() {
            if(fSession != null) {
                try {
                    if(fSession.Transacted) {
                        if(fCommitVote && !fRollbackVote)
                            fSession.Commit();
                        else
                            fSession.Rollback();
                    }
                }
                finally {
                    if(fCloseSession)
                        fSession.Dispose();
                    fSession = null;
                }
            }
        }

        #endregion
    }
}

